﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Lookstone
{
	public class Convert
	{
		public static int ReverseInt(int sourceInt)
		{
			// Reverse the order of the bytes
			byte[] byteVal = System.BitConverter.GetBytes(sourceInt);
			byte[] newBytes = new byte[4];

			newBytes[0] = byteVal[3];
			newBytes[1] = byteVal[2];
			newBytes[2] = byteVal[1];
			newBytes[3] = byteVal[0];

			return System.BitConverter.ToInt32(newBytes, 0);
		}

		public static ushort ReverseShort(ushort source)
		{
			// Reverse the order of the bytes
			byte[] byteVal = System.BitConverter.GetBytes(source);
			byte[] newBytes = new byte[2];

			newBytes[0] = byteVal[1];
			newBytes[1] = byteVal[0];

			return (ushort)System.BitConverter.ToInt16(newBytes, 0);
		}

		public static double PercentStringToDouble(string val)
		{
			double newVal = 0.0;

			if (double.TryParse(val, out newVal))
			{
				newVal /= 100.0;
				newVal = System.Math.Round(newVal, 6);
			}

			return newVal;
		}

		public static string DoubleToPercentString(double val)
		{
			val *= 100.0;
			return string.Format("{0:F4}", val);
		}

		public static string PhoneNumberString(string phoneNum)
		{
			StringBuilder builder = new StringBuilder(15);

			for (int pos = 0; pos < phoneNum.Length; pos++)
			{
				if (char.IsDigit(phoneNum[pos]))
					builder.Append(phoneNum[pos]);
			}

			// Format the phone number.
			if (builder.Length == 7)
				builder.Insert(3, '-');
			else if (builder.Length == 10)
			{
				builder.Insert(6, '-');
				builder.Insert(3, ") ");
				builder.Insert(0, '(');
			}

			return builder.ToString();
		}

		public static string ZipCodeString(string zipCode)
		{
			if (zipCode.Length == 9)
				return zipCode.Substring(0, 5) + "-" + zipCode.Substring(5);
			else if (zipCode.Length == 6)
				return zipCode.Substring(0, 3) + " " + zipCode.Substring(3);
			else
				return zipCode;
		}

		public static string PhoneNumberValue(string phoneNumString)
		{
			if (string.IsNullOrEmpty(phoneNumString))
				return string.Empty;

			StringBuilder builder = new StringBuilder(15);

			for (int pos = 0; pos < phoneNumString.Length; pos++)
			{
				if (char.IsDigit(phoneNumString[pos]))
					builder.Append(phoneNumString[pos]);
			}

			return builder.ToString();
		}

		#region //****** Value Types ******//
		public static long StringToLong(string val)
		{
			long newVal = 0;

			if (string.IsNullOrWhiteSpace(val))
				return newVal;

			long.TryParse(val, out newVal);
			return newVal;
		}

		public static int StringToInt(string val)
		{
			int newVal = 0;

			if (string.IsNullOrWhiteSpace(val))
				return newVal;

			int.TryParse(val, out newVal);
			return newVal;
		}

		public static int? StringToNullableInt(string val)
		{
			if (string.IsNullOrWhiteSpace(val))
				return null;

			int newVal = 0;

			if (int.TryParse(val, out newVal))
				return newVal;

			return null;
		}

		public static int StringToInt(string val, int defaultValue)
		{
			int newVal = defaultValue;

			if (string.IsNullOrWhiteSpace(val))
				return newVal;

			if (!int.TryParse(val, out newVal))
				newVal = defaultValue;

			return newVal;
		}

		public static short StringToShort(string val)
		{
			short newVal = 0;

			if (string.IsNullOrWhiteSpace(val))
				return newVal;

			short.TryParse(val, out newVal);
			return newVal;
		}

		public static byte StringToByte(string val)
		{
			byte newVal = 0;

			if (string.IsNullOrWhiteSpace(val))
				return newVal;

			byte.TryParse(val, out newVal);
			return newVal;
		}

		public static float StringToFloat(string val)
		{
			float newVal = 0.0f;

			if (string.IsNullOrWhiteSpace(val))
				return newVal;

			float.TryParse(val, out newVal);
			return newVal;
		}

		public static float? StringToNullableFloat(string val)
		{
			if (string.IsNullOrWhiteSpace(val))
				return null;

			float newVal = 0.0f;

			if (float.TryParse(val, out newVal))
				return newVal;

			return null;
		}

		public static double StringToDouble(string val)
		{
			double newVal = 0.0;

			if (string.IsNullOrWhiteSpace(val))
				return newVal;

			double.TryParse(val, out newVal);
			return newVal;
		}

		public static decimal StringToDecimal(string val)
		{
			decimal newVal = 0m;

			if (string.IsNullOrWhiteSpace(val))
				return newVal;

			decimal.TryParse(val, out newVal);
			return newVal;
		}

		public static Guid StringToGuid(string val)
		{
			Guid newVal = Guid.Empty;

			if (string.IsNullOrWhiteSpace(val))
				return newVal;

			Guid.TryParse(val, out newVal);
			return newVal;
		}

		public static Guid? StringToNullableGuid(string val)
		{
			if (string.IsNullOrWhiteSpace(val))
				return null;

			Guid newVal = Guid.Empty;

			if (Guid.TryParse(val, out newVal))
				return newVal;

			return null;
		}

		/// <summary>
		/// Converts a string into a boolean value
		/// </summary>
		/// <param name="val">the value to parse and determine if it is a boolean</param>
		/// <param name="useAdvancedVocabulary">if false, it only cares about true/false, if it is true, it cares about "on", "yes", and "1"</param>
		/// <returns>the value as a boolean; defaults to false if it can't figure it out</returns>
		public static bool StringToBool(string val, bool useAdvancedVocabulary = false)
		{
			bool newVal = false;

			if (string.IsNullOrWhiteSpace(val))
				return newVal;

			if (useAdvancedVocabulary)
				return string.Compare("on", val, true) == 0 || string.Compare("yes", val, true) == 0 || val.CompareTo("1") == 0 || string.Compare("true", val, true) == 0;
			else
				bool.TryParse(val, out newVal);

			return newVal;
		}
		#endregion //****** Value Types ******//

		public static int ObjectToInt(object val)
		{
			int newVal = 0;

			if (val == null)
				return newVal;

			try
			{
				newVal = System.Convert.ToInt32(val);
			}
			catch
			{
				newVal = 0;
			}

			return newVal;
		}

		public static string DateTimeToString(DateTime date)
		{
			return date.ToString("MM/dd/yyyy");
		}

		public static string NumberToExtendedNameString(long number)
		{
			int num = (int)(number % 10);
			int lessThanHundred = (int)number % 100;

			if (num == 1 && lessThanHundred != 11)
				return "st";
			else if (num == 2 && lessThanHundred != 12)
				return "nd";
			else if (num == 3 && lessThanHundred != 13)
				return "rd";

			return "th";
		}

		public static string BoolToYesNoString(bool val)
		{
			if (val)
				return "Yes";

			return "No";
		}

		public static string IntToVerboseString(long val)
		{
			StringBuilder builder = new StringBuilder(75);
			string orgNum = val.ToString();

			//Build the textual representation of the dollar amount
			int nPlace;
			bool tens = false;
			bool hundreds = false;

			nPlace = orgNum.Length - 1;

			for (int x = 0; x < orgNum.Length; x++)
			{
				switch (orgNum[x])
				{
					case '0':
						if (tens)
						{
							builder.Append("Ten ");
							tens = false;
						}
						break;

					case '1':
						if ((x == orgNum.Length - 2) || (x == orgNum.Length - 5) || (x == orgNum.Length - 8) || (x == orgNum.Length - 11))
							tens = true;
						if ((x == orgNum.Length - 3) || (x == orgNum.Length - 6) || (x == orgNum.Length - 9) || (x == orgNum.Length - 12))
							hundreds = true;

						if (tens)
						{
							switch (orgNum[x + 1])
							{
								case '0':
									builder.Append("Ten ");
									break;
								case '1':
									builder.Append("Eleven ");
									break;
								case '2':
									builder.Append("Twelve ");
									break;
								case '3':
									builder.Append("Thirteen ");
									break;
								case '4':
									builder.Append("Fourteen ");
									break;
								case '5':
									builder.Append("Fifteen ");
									break;
								case '6':
									builder.Append("Sixteen ");
									break;
								case '7':
									builder.Append("Seventeen ");
									break;
								case '8':
									builder.Append("Eighteen ");
									break;
								case '9':
									builder.Append("Nineteen ");
									break;
							}
							tens = false;
						}
						else if (hundreds)
						{
							builder.Append("One ");
							hundreds = false;
							break;
						}
						else
						{
							if (x == 0)
								builder.Append("One ");
							else
							{
								if (orgNum[x - 1] == '1')
									break;
								builder.Append("One ");
							}
						}
						break;

					case '2':
						if ((x == orgNum.Length - 2) || (x == orgNum.Length - 5) || (x == orgNum.Length - 8) || (x == orgNum.Length - 11))
						{
							builder.Append("Twenty ");
							break;
						}

						if ((x == orgNum.Length - 3) || (x == orgNum.Length - 6) || (x == orgNum.Length - 9) || (x == orgNum.Length - 12))
						{
							builder.Append("Two ");
							break;
						}

						if (tens)
						{
							builder.Append("Twelve ");
							tens = false;
							break;
						}
						else
						{
							if (x > 0 && orgNum[x - 1] == '1')
								break;
							builder.Append("Two ");
						}

						break;

					case '3':
						if ((x == orgNum.Length - 2) || (x == orgNum.Length - 5) || (x == orgNum.Length - 8) || (x == orgNum.Length - 11))
						{
							builder.Append("Thirty ");
							break;
						}

						if ((x == orgNum.Length - 3) || (x == orgNum.Length - 6) || (x == orgNum.Length - 9) || (x == orgNum.Length - 12))
						{
							builder.Append("Three ");
							break;
						}

						if (tens)
							builder.Append("Thirteen ");
						else
						{
							if (x > 0 && orgNum[x - 1] == '1')
								break;
							builder.Append("Three ");
						}
						break;

					case '4':
						if ((x == orgNum.Length - 2) || (x == orgNum.Length - 5) || (x == orgNum.Length - 8) || (x == orgNum.Length - 11))
						{
							builder.Append("Forty ");
							break;
						}

						if ((x == orgNum.Length - 3) || (x == orgNum.Length - 6) || (x == orgNum.Length - 9) || (x == orgNum.Length - 12))
						{
							builder.Append("Four ");
							break;
						}

						if (tens)
							builder.Append("Forteen ");
						else
						{
							if (x > 0 && orgNum[x - 1] == '1')
								break;
							builder.Append("Four ");
						}
						break;

					case '5':
						if ((x == orgNum.Length - 2) || (x == orgNum.Length - 5) || (x == orgNum.Length - 8) || (x == orgNum.Length - 11))
						{
							builder.Append("Fifty ");
							break;
						}

						if ((x == orgNum.Length - 3) || (x == orgNum.Length - 6) || (x == orgNum.Length - 9) || (x == orgNum.Length - 12))
						{
							builder.Append("Five ");
							break;
						}

						if (tens)
							builder.Append("Fifteen ");
						else
						{
							if (x > 0 && orgNum[x - 1] == '1')
								break;
							builder.Append("Five ");
						}
						break;

					case '6':
						if ((x == orgNum.Length - 2) || (x == orgNum.Length - 5) || (x == orgNum.Length - 8) || (x == orgNum.Length - 11))
						{
							builder.Append("Sixty ");
							break;
						}

						if ((x == orgNum.Length - 3) || (x == orgNum.Length - 6) || (x == orgNum.Length - 9) || (x == orgNum.Length - 12))
						{
							builder.Append("Six ");
							break;
						}

						if (tens)
							builder.Append("Sixteen ");
						else
						{
							if (x > 0 && orgNum[x - 1] == '1')
								break;
							builder.Append("Six ");
						}
						break;

					case '7':
						if ((x == orgNum.Length - 2) || (x == orgNum.Length - 5) || (x == orgNum.Length - 8) || (x == orgNum.Length - 11))
						{
							builder.Append("Seventy ");
							break;
						}

						if ((x == orgNum.Length - 3) || (x == orgNum.Length - 6) || (x == orgNum.Length - 9) || (x == orgNum.Length - 12))
						{
							builder.Append("Seven ");
							break;
						}

						if (tens)
							builder.Append("Seventeen ");
						else
						{
							if (x > 0 && orgNum[x - 1] == '1')
								break;
							builder.Append("Seven ");
						}
						break;

					case '8':
						if ((x == orgNum.Length - 2) || (x == orgNum.Length - 5) || (x == orgNum.Length - 8) || (x == orgNum.Length - 11))
						{
							builder.Append("Eighty ");
							break;
						}

						if ((x == orgNum.Length - 3) || (x == orgNum.Length - 6) || (x == orgNum.Length - 9) || (x == orgNum.Length - 12))
						{
							builder.Append("Eight ");
							break;
						}

						if (tens)
							builder.Append("Eighteen ");
						else
						{
							if (x > 0 && orgNum[x - 1] == '1')
								break;
							builder.Append("Eight ");
						}
						break;

					case '9':
						if ((x == orgNum.Length - 2) || (x == orgNum.Length - 5) || (x == orgNum.Length - 8) || (x == orgNum.Length - 11))
						{
							builder.Append("Ninety ");
							break;
						}

						if ((x == orgNum.Length - 3) || (x == orgNum.Length - 6) || (x == orgNum.Length - 9) || (x == orgNum.Length - 12))
						{
							builder.Append("Nine ");
							break;
						}

						if (tens)
							builder.Append("Nineteen ");
						else
						{
							if (x > 0 && orgNum[x - 1] == '1')
								break;
							builder.Append("Nine ");
						}
						break;
				}

				if (orgNum.Length >= 3)
				{
					switch (nPlace)
					{
						case 2:
							if (orgNum[x] != '0')
								builder.Append("Hundred ");
							break;

						case 3:
							{
								// if the number before x is less than 1, and if x > 0, add "Thousand "
								// EXCEPT if in the millions
								if (x > 0 && orgNum[x] == '0')
								{
									if (orgNum[x - 1] <= '1')
									{
										if (orgNum.Length > 6 && builder.ToString(builder.Length - 8, 8) != "Hundred ")
										{
											//do nothing
											break;
										}
										else
										{
											builder.Append("Thousand ");
											break;
										}
									}
									else
										builder.Append("Thousand ");
								}
								if (orgNum[x] != '0')
								{
									builder.Append("Thousand ");
								}
								break;
							}

						case 5:
							if (orgNum[x] != '0')
								builder.Append("Hundred ");
							break;

						case 6:
							if (orgNum[x] != '0')
								builder.Append("Million ");
							break;

						case 8:
							if (orgNum[x] != '0')
								builder.Append("Hundred ");
							break;
					}
				}
				nPlace--;
			}

			return builder.ToString();
		}

		// Encodes a standard string into string that may be sent over an internet URL
		public static string HexEncode(string toEncode)
		{
			StringBuilder builder = new StringBuilder();
			char curChar;

			if (toEncode.Length == 0)
				return toEncode;

			for (int pos = 0; pos < toEncode.Length; pos++)
			{
				curChar = toEncode[pos];

				if ((curChar >= 'a' && curChar <= 'z') ||
					(curChar >= 'A' && curChar <= 'Z') ||
					(curChar >= '0' && curChar <= '9'))
				{
					builder.Append(curChar);
				}
				else
				{
					builder.AppendFormat("%{0:X2}", (byte)curChar);
				}
			}
			return builder.ToString();
		}

		/// <summary>
		/// Given a string, encode it to Base64 encoding and return the result
		/// </summary>
		/// <param name="value"></param>
		/// <returns></returns>
		public static string ToBase64String(string value)
		{
			byte[] bytes = System.Text.ASCIIEncoding.UTF8.GetBytes(value);
			string encoded = System.Convert.ToBase64String(bytes);

			return encoded;
		}

		/// <summary>
		/// Given a string encoded with Base64 encoding, return the value; optionally return original value if exception is thrown
		/// </summary>
		/// <param name="value"></param>
		/// <param name="throwException">If true, throws an exception when decoding fails; if false, returns original value if decoding fails</param>
		/// <returns></returns>
		public static string FromBase64String(string value, bool throwException = true)
		{
			try
			{
				byte[] decodedBytes = System.Convert.FromBase64String(value);
				string decoded = System.Text.Encoding.UTF8.GetString(decodedBytes);

				return decoded;
			}
			catch (Exception ex)
			{
				if (throwException)
					throw new Exception(ex.Message, ex);
				else
					return value;
			}
		}

		public static class Currency
		{
			public static decimal CentsToDecimal(long cents)
			{
				decimal val = (decimal)(cents);

				val /= 100m;
				return val;
			}

			public static int DecimalToCentsInt32(decimal value)
			{
				return System.Convert.ToInt32(value * 100m);
			}
		}
	}
}
